package com.mall.order.services;

import com.mall.commons.result.AbstractResponse;
import com.mall.order.OrderCoreService;
import com.mall.order.biz.TransOutboundInvoker;
import com.mall.order.biz.context.AbsTransHandlerContext;
import com.mall.order.biz.context.TransHandlerContext;
import com.mall.order.biz.factory.CancelOrderPipelineFactory_X;
import com.mall.order.biz.factory.OrderProcessPipelineFactory;
import com.mall.order.constant.OrderRetCode;
import com.mall.order.constants.OrderConstants;
import com.mall.order.dal.entitys.Order;
import com.mall.order.dal.entitys.OrderItem;
import com.mall.order.dal.entitys.Stock;
import com.mall.order.dal.persistence.OrderItemMapper;
import com.mall.order.dal.persistence.OrderMapper;
import com.mall.order.dal.persistence.OrderShippingMapper;
import com.mall.order.dal.persistence.StockMapper;
import com.mall.order.dto.*;
import com.mall.order.utils.ExceptionProcessorUtils;
import com.mall.shopping.constants.ShoppingRetCode;
import com.mall.user.constants.SysRetCodeConstants;
import com.sun.org.apache.xpath.internal.operations.Or;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;

/**
 * cskaoyan
 */
@Slf4j
@Component
// 集群容错策略  快速失败，仅发起一次调用，失败立即报错  常用于非幂等性写操作  新增记录
// 非幂等性操作：每一次调用都对资源本身产生影响  写操作：每次调用都会新增资源
@Service(cluster = "failfast")
public class OrderCoreServiceImpl implements OrderCoreService {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    OrderItemMapper orderItemMapper;

    @Autowired
    OrderShippingMapper orderShippingMapper;

    @Autowired
    OrderProcessPipelineFactory orderProcessPipelineFactory;

    @Autowired
    CancelOrderPipelineFactory_X cancelOrderPipelineFactory;   //这个才是我们真正要去实现的东西

    @Autowired
    StockMapper stockMapper;


    /**
     * 创建订单的处理流程
     *
     * @param request
     * @return
     */
    @Override
    public CreateOrderResponse createOrder(CreateOrderRequest request) {
        CreateOrderResponse response = new CreateOrderResponse();
        try {
            // 请求参数校验
            request.requestCheck();

            //创建pipeline对象
            TransOutboundInvoker invoker = orderProcessPipelineFactory.build(request);

            //启动pipeline
            invoker.start(); //启动流程（pipeline来处理）

            //获取处理结果
            AbsTransHandlerContext context = invoker.getContext();

            //把处理结果转换为response
            response = (CreateOrderResponse) context.getConvert().convertCtx2Respond(context);
        } catch (Exception e) {
            log.error("OrderCoreServiceImpl.createOrder Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }


    /**
     * 订单取消------------使用pipeline方式(暂时没有使用)
     *
     * @param request
     * @return
     */
    @Override
    public CancelOrderResponse cancelOrder(CancelOrderRequest request) {
        //1.定义响应Response
        CancelOrderResponse response = new CancelOrderResponse();

        try {
            //请求参数校验
            request.requestCheck();

            //需要知道:pipeline设计模式、可能需要使用的转化器
            //此处的：pipeline和demo级别的相比较而言：稍微复杂  复杂是：使用工厂模式创建pipeline  &  创建配套的context 、 handler 、 converter

            //1.创建pipeline对象（使用工厂模式）:将request转化为context，同时：按照尾插法顺序添加多个handler   添加到pipeline  启动pipeline
            TransOutboundInvoker invoker = cancelOrderPipelineFactory.build(request);   //MD:没有对应的创建方法；分析：也许是取消订单，不需要使用pipeline***********去验证一下，哈哈；好吧，
            // 需要使用pipeline解决多个相关流程环节;没有的部分，自己创建

            //2.启动pipeline：内部：head.getNext().exec(getContext()); 将context交给exec处理：一个一个handler进行实际的处理（涉及回调函数和异常处理handler，仅仅提供优化模式思路）
            invoker.start();

            //3.获取pipeline处理结果
            AbsTransHandlerContext context = invoker.getContext();

            //4.将处理结果转化为可以response的形式
            response = (CancelOrderResponse) context.getConvert().convertCtx2Respond(context);

            //根据返回参数格式，进行设置      **************************后续测试结果不通过，直接使用CreateOrder部分


            //TransConvert已经从context转化为response，对response进行了封装，所以，下述方式，不需要重复

//			response.setCode(OrderRetCode.SUCCESS.getCode());
//			response.setMsg(OrderRetCode.SUCCESS.getMessage());
//			response.setResult("成功");
//		}catch (Exception e) {
////			log.error("OrderCoreServiceImpl.createOrder Occur Exception :" + e);
////			ExceptionProcessorUtils.wrapperHandlerException(response, e);
//			//从购物车转接过来的响应方式
//			e.printStackTrace();
//			response.setCode(OrderRetCode.DB_EXCEPTION.getCode());
//			response.setMsg(OrderRetCode.DB_EXCEPTION.getMessage());
//		}
//		return response;

        } catch (Exception e) {
            log.error("OrderCoreServiceImpl.createOrder Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }


    @Override
    public DeleteOrderResponse deleteOrder(DeleteOrderRequest deleteOrderRequest) {
        DeleteOrderResponse deleteOrderResponse = new DeleteOrderResponse();
        try {
            //参数校验
            deleteOrderRequest.requestCheck();
            // 删除tb_order表中的数据
            int deleteOrderEffectRow = orderMapper.deleteByPrimaryKey(deleteOrderRequest.getOrderId());
            // 删除tb_order_item中的数据
            Example orderItemExample = new Example(OrderItem.class);
            orderItemExample.createCriteria().andEqualTo("orderId", deleteOrderRequest.getOrderId());
            int deleteOrderItemEffectRow = orderItemMapper.deleteByExample(orderItemExample);
            //删除tb_order_shipping
            int deleteOrderShippingEffectRow = orderShippingMapper.deleteByPrimaryKey(deleteOrderRequest.getOrderId());
            if (deleteOrderEffectRow != 1 || deleteOrderItemEffectRow == 0 || deleteOrderShippingEffectRow != 1) {
                // 任何一个删除有问题就返回异常信息
                deleteOrderResponse.setCode(SysRetCodeConstants.DB_EXCEPTION.getCode());
                deleteOrderResponse.setMsg(SysRetCodeConstants.DB_EXCEPTION.getMessage());
                return deleteOrderResponse;
            }
            // 成功
            deleteOrderResponse.setCode(SysRetCodeConstants.SUCCESS.getCode());
            deleteOrderResponse.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("OrderCoreServiceImpl.deleteOrder Occur Exception:" + e);
            deleteOrderResponse.setCode(SysRetCodeConstants.SYSTEM_ERROR.getCode());
            deleteOrderResponse.setMsg(SysRetCodeConstants.SYSTEM_ERROR.getMessage());
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(deleteOrderResponse, e);
        }
        return deleteOrderResponse;
    }

    /**
     * 支付成功时，更新订单状态，更新锁定库存（非pipeline模式）
     *
     * @param request
     * @return
     */
    @Override
    public PayOrderSuccessResponse payOrderSuccess(PayOrderSuccessRequest request) {   //传入订单id
        //0.response封装
        PayOrderSuccessResponse response = new PayOrderSuccessResponse();
        try {
            request.requestCheck();
            //1.修改订单相应的数据: 修改订单的状态为已支付
//			Example example = new Example(Order.class);
            Example example = new Example(Order.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("orderId", request.getOrderId());   //******

            Order order = new Order();
            order.setStatus(1);   //已付款状态
            orderMapper.updateByExampleSelective(order, example);

            //2.遍历订单中的订单商品条目，根据订单商品条目中商品购买的数量，去扣减对应商品的锁定库存
            //根据orderId，tb_order_item表，获取多个ItemId及对应的购买数量
            //根据ItemId,tb_stock表,lock_count-购买数量
            Example example1 = new Example(OrderItem.class);
            Example.Criteria criteria1 = example1.createCriteria();
            criteria1.andEqualTo("orderId", request.getOrderId());
            List<OrderItem> orderItems = orderItemMapper.selectByExample(example1);  //根据orderId，在tb_order_item表，获取多个ItemId及对应的购买数量

            Example example2 = new Example(Stock.class);
            Example.Criteria criteria2 = example2.createCriteria();
            for (OrderItem orderItem : orderItems) {  //遍历多个order_items
                //订单id-ItemId
                Long itemId = orderItem.getItemId();

                //ItemId对应的购买数量
                Integer num = orderItem.getNum();

                //根据ItemId,在tb_stock表,lock_count-购买数量

                criteria2.andEqualTo("itemId",itemId);

                Stock stock = new Stock();
                stock.setLockCount(-num);
                stock.setItemId(itemId);
                stock.setStockCount(num.longValue());
                stockMapper.updateStock(stock);
            }

            //3.返回查询结果的响应  SUCCESS
            response.setCode(SysRetCodeConstants.SUCCESS.getCode());
            response.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("OrderCoreServiceImpl.payOrderSuccess Occur Exception:"+e);
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }
}
